#include <QDebug>
#include "AnimTrack.h"
#include "AnimMontage_p.h"
#include "AnimMontageUtils.h"

using namespace QSSGSceneDesc;

AnimTrack::AnimTrack()
{

}

template<typename T>
void getValue(std::optional<T>& value,float current,Animation::Channel *channel){
    int first = -1,last = -1;
    for(int i = 0;i<channel->keys.size();i++)
    {
        const auto & key = channel->keys[i];
        last = i;
        if(key->time >= current)
        {
            break;
        }
        first = last;
    }

    if(first == -1 && last == -1)//没有关键帧
    {
        return;
    }
    else if(first == last || first == -1)//在第一帧前或者在最后一帧后
    {
        value = channel->keys[last]->getValue().value<T>();
    }
    else{
        auto k1 = channel->keys[first],k2 = channel->keys[last];
        float alpha = (current - k1->time) / (k2->time - k1->time);

        value = AnimMontageUtils::inter(k1->getValue().value<T>(),k2->getValue().value<T>(),alpha);
    }
}

Pose AnimTrack::getEntry()
{
    if(!m_source)
    {
        return {};
    }

    auto _P = m_source->_P;
    QMutexLocker locker(&_P->mutex);
    if(!_P->scene)
    {
        return {};
    }
    auto scene = _P->scene;
    auto index = m_index;
    auto movement = m_movement;
    double integerPart;
    movement = modf(movement, &integerPart);

    if(scene->animations.count() <= index)
    {
        return {};
    }

    Pose ret;

    const auto& animation = scene->animations[index];
    auto current = movement * animation->length;

    for(const auto &channel:animation->channels)
    {
        QByteArray targetId;
        auto property = channel->targetProperty;
        QByteArray propertyStr;
        targetId = channel->target->name;

        if(property == Animation::Channel::TargetProperty::Position)
        {
            getValue(ret[targetId].position,current,channel);
        }
        else if(property == Animation::Channel::TargetProperty::Rotation)
        {
            getValue(ret[targetId].rotation,current,channel);
        }
        else if(property == Animation::Channel::TargetProperty::Scale)
        {
            getValue(ret[targetId].scale,current,channel);
        }
        else{
            continue;
        }  
    }

    return ret;
}

AnimSource *AnimTrack::source() const
{
    return m_source;
}

void AnimTrack::setSource(AnimSource *newSource)
{
    if (m_source == newSource)
        return;
    m_source = newSource;
    emit sourceChanged();
}

float AnimTrack::index() const
{
    return m_index;
}

void AnimTrack::setIndex(float newIndex)
{
    if (qFuzzyCompare(m_index, newIndex))
        return;
    m_index = newIndex;
    emit indexChanged();
}

float AnimTrack::movement() const
{
    return m_movement;
}

void AnimTrack::setMovement(float newMovement)
{
    if (qFuzzyCompare(m_movement, newMovement))
        return;
    m_movement = newMovement;
    emit movementChanged();
}
